package org.hy.pay.message.util;

/**
 * 
 */

import java.beans.IntrospectionException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.hy.pay.common.core.page.PageBean;
import org.hy.pay.common.core.utils.DateUtils;
import org.hy.pay.common.core.utils.StringUtil;
import org.hy.pay.message.exception.MessageBizException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonFormat;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;


/**
 * @author lzm
 * @Date 2017-11-06
 * @version 1.0v
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class ConfigData {
	
	private static final Logger logger = LoggerFactory.getLogger(ConfigData.class);
	
	private static final String STR_SEPARATOR = ",";
	private static final String EMPTY_STR = "";
	
	/**
	 * 加载配置文件
	 * @param version
	 * @return
	 */
	private static SystemProperties initProperty(String version){
		version = version == null ? "" : "_"+version;
		SystemProperties p = SystemProperties.getInstance("config/returnFields"+version+".properties");
		return p;
	}
	
	/**
	 * 封装字段
	 * @param obj
	 * @return
	 * @throws MessageBizException
	 */
	public static String  process(Object obj) throws MessageBizException{
		return process(obj, null, null);
	}
	
	/**
	 * 封装字段
	 * @param obj 需要封装的对象
	 * 
	 * @param key 传入映射资源名
	 *  	e.g. @Path("/queryUserDetailById") key="queryUserDetailById"
	 * @return
	 * @throws MessageBizException
	 * @throws IOException 
	 */
	public static String  process(Object obj, String key, String version) throws MessageBizException{
		
		String result = null;
		if(obj instanceof Collection){
			result = processList((Collection<Object>)obj, key, version);
		}else if(obj instanceof Map){
			result = processMap((Map<Object, Object>)obj, key, version);
		}
	/*	else if(obj instanceof Page){
			result = processPage((Page)obj, key, version);
		}*/
		else{
		//	JSONArray resultArray = new JSONArray();
			JSONObject json = processObj(obj, key, version);
			if(!json.isNullObject() && !json.isEmpty())
			//	resultArray.add(json);
			result = json.toString();
		}
		return result;
	}
	
	/**
	 * 处理单个对象
	 * @param obj
	 * @param key
	 * @return
	 * @throws MessageBizException
	 */
	public static JSONObject processObj(Object obj, String key, String version) throws MessageBizException{
		return envelopData(obj, key, version);
	}

	/**
	 * 处理集合
	 * @param objs
	 * @param key
	 * @return
	 * @throws MessageBizException
	 */
	private static String processList(Collection<Object> objs, String key, String version) throws MessageBizException{
		JSONArray fieldArray = new JSONArray();
		if(null!=objs && !objs.isEmpty()){
			for(Object obj : objs){
				JSONObject envelopData = envelopData(obj, key, version);
				if(!envelopData.isNullObject() && !envelopData.isEmpty())
					fieldArray.add(envelopData);
			}
		}
		return fieldArray.toString();
	}
	//
	
	@SuppressWarnings("unused")
	private static <T> String processPage(PageBean<T> page, String key, String version) throws MessageBizException{
		JSONArray fieldArray = new JSONArray();
		if(null!=page ){
			for(Object obj : page.getRecordList()){
				JSONObject envelopData = envelopData(obj, key, version);
				if(!envelopData.isNullObject() && !envelopData.isEmpty())
					fieldArray.add(envelopData);
			}
		}
		return fieldArray.toString();
	}

	/**
	 * 封装字段数据
	 * @param obj
	 * @param returnFields
	 * @return
	 * @throws MessageBizException
	 * @throws IntrospectionException 
	 */
	private static JSONObject envelopData(Object obj, String key, String version) throws MessageBizException {
		JSONObject returnJson = new JSONObject();
		if(obj == null){
			return returnJson;
		}
		
		if(key == null || key.isEmpty()){
			envelopDefaultFields(obj, returnJson);
			return returnJson;
		}
		SystemProperties p = initProperty(version);
		String configField = p.getProperty(key);
		if(configField == null || configField.isEmpty()){
			throw new MessageBizException(MessageBizException.FIELD_CONF_ERROR,"字段配置错误");
		}
		
		return envelopSelfDefinedFields(obj, key, configField, returnJson, version);
	}

	/**
	 * 封装自定义字段
	 * @param obj
	 * @param key
	 * @param returnFields
	 * @param returnJson
	 * @return
	 * @throws MessageBizException
	 */
	private static JSONObject envelopSelfDefinedFields(Object obj, String key,
			String configField, JSONObject returnJson, String version)
			throws MessageBizException {
		Field field = null;
		String[] returnFields = configField.split(STR_SEPARATOR);
		//封装的是基本类型
		if(isPrimitive(obj.getClass())){
			returnJson.put(returnFields[0], obj);
		}else{
			for(String returnField : returnFields){
				if(!existsField(obj.getClass(), returnField)) continue;
				field = getFieldByName(obj.getClass(), returnField);
				field.setAccessible(true);
				String name = field.getName();
				Class<?> type = field.getType();
				Object value = null;
				try {
					value = field.get(obj);
				} catch (Exception e) {
					logger.error("DataHandler.process get field="+name+" value error\r\n"+e.toString());
					throw new MessageBizException(MessageBizException.NO_SUCH_FIELD_ERROR,"找不到此字段");
				}
				if(!isPrimitive(type)){
					String fieldValue = null;
					if(isCollection(type)){
						fieldValue = processList((Collection<Object>)value, key+"."+name, version);
					}else if(type.isArray()){
						fieldValue = processArray((Object[])value, key+"."+name, version);
					}else if(isMap(type)){
						fieldValue = processMap((Map)value, key+"."+name, version);
					}else{
						JSONObject json = processObj(value, key+"."+name, version);
						fieldValue = json.toString();
					}
					returnJson.put(returnField, fieldValue);
				}else {
					if(isNumeric(type)){
						value = value == null ? 0 : value;
					}else if(isDate(type)){
						String fkey = returnField+"Str";
						String val = "";
						if(value != null){
							DateTimeFormat ft = field.getAnnotation(DateTimeFormat.class);
							String pattern = null;
							if(ft != null){
								pattern = ft.pattern();
							}else{
								JsonFormat jft = field.getAnnotation(JsonFormat.class);
								if(jft != null){
									pattern = jft.pattern();
								}
							}
							if(StringUtil.isEmpty(pattern)){
								pattern = "yyyy-MM-dd HH:mm:ss";
							}
							val = DateUtils.formatDate((Date)value, pattern);
						}
						returnJson.put(fkey, val);
					}else{
						value = value == null ? "" : value;
					}
					returnJson.put(returnField, value);
				}
			}
		}
		return returnJson;
	}

	/**
	 * 封装默认字段(没有传入key的默认为全部字段)
	 * @param obj
	 * @param returnJson
	 * @throws MessageBizException
	 */
	private static void envelopDefaultFields(Object obj, JSONObject returnJson)
			throws MessageBizException {
		if(isPrimitive(obj.getClass())){
			returnJson.put("value", obj);
		}else{
			envelopAllFields(obj, obj.getClass(), returnJson);
		}
	}

	/**
	 * 获取字段
	 * @param clazz
	 * @param field
	 * @param returnField
	 * @return
	 * @throws MessageBizException
	 */
	private static Field getFieldByName(Class<?> clazz, String returnField) throws MessageBizException {
		try{
			return clazz.getDeclaredField(returnField);
		}catch(Exception e){
			Class<?> superclass = clazz.getSuperclass();
			if(superclass != null && !superclass.isAssignableFrom(Object.class)){
				return getFieldByName(superclass, returnField);
			}else{
				logger.error("DataHandler.process cann`t find field="+returnField+"\r\n"+e.toString());
				throw new MessageBizException(MessageBizException.NO_SUCH_FIELD_ERROR,"找不到字段");
			}
		}
	}
	
	/**
	 * 获取本类及父类所有的字段
	 * @param obj
	 * @param clazz
	 * @param returnJson
	 * @throws MessageBizException
	 */
	private static void envelopAllFields(Object obj, Class<?> clazz, JSONObject returnJson) throws MessageBizException{
		Class<?> superclass = clazz.getSuperclass();
		if(null != superclass && !superclass.isAssignableFrom(Object.class)){
			envelopAllFields(obj, superclass, returnJson);
		}
		Field[] fieldArray = clazz.getDeclaredFields();
		for(Field field : fieldArray){
			String name = field.getName();
			
			if("serialVersionUID".equals(name)){
				continue;
			}
			field.setAccessible(true);
			Class<?> type = field.getType();
			Object value = null;
			try {
				value = field.get(obj);
			} catch (Exception e) {
				logger.error("DataHandler.process get field="+name+" value error\r\n"+e.toString());
				throw new MessageBizException(MessageBizException.NO_SUCH_FIELD_ERROR,"找不到此字段");
			}
			if(!isPrimitive(type)){
				String fieldValue = null;
				if(isCollection(type)){
					fieldValue = processList((Collection)value, null, null);
				}else if(type.isArray()){
					fieldValue = processArray((Object[])value, null, null);
				}else if(isMap(type)){
					fieldValue = processMap((Map)value, null, null);
				}else{
					JSONObject json = processObj(value, null, null);
					fieldValue = json.toString();
				}
				returnJson.put(field.getName(), fieldValue);
			}else {
				if(isNumeric(type)){
					value = value == null ? 0 : value;
				}else if(isDate(type)){
					String fkey = field.getName()+"Str";
					String val = "";
					if(value != null){
						DateTimeFormat ft = field.getAnnotation(DateTimeFormat.class);
						String pattern = null;
						if(ft != null){
							pattern = ft.pattern();
						}else{
							JsonFormat jft = field.getAnnotation(JsonFormat.class);
							if(jft != null){
								pattern = jft.pattern();
							}
						}
						if(StringUtil.isEmpty(pattern)){
							pattern = "yyyy-MM-dd HH:mm:ss";
						}
						val = DateUtils.formatDate((Date)value, pattern);
					}
					returnJson.put(fkey, val);
				}else{
					value = value == null ? "" : value;
				}
				returnJson.put(field.getName(), value);
			}
		}
	}
	

	/**
	 * 处理map字段
	 * @param value
	 * @param key
	 * @return
	 * @throws MessageBizException 
	 */
	private static String processMap(Map<Object,Object> value, String key, String version) throws MessageBizException {
		JSONArray jsonArray = new JSONArray();
		JSONObject jsonObject = new JSONObject();
		if(null != value && !value.isEmpty()){
			Set<Entry<Object, Object>> entrySet = value.entrySet();
			for(Entry<Object, Object> e : entrySet){
				if(null == e.getValue()){
					jsonObject.put(e.getKey(), EMPTY_STR);
				}else if(isPrimitive(e.getValue().getClass())){
					jsonObject.put(e.getKey(), e.getValue());
				}else if(isCollection(e.getValue().getClass())){
					jsonObject.put(e.getKey(), processList((Collection)e.getValue(), key, version));
				}else if(isMap(e.getValue().getClass())){
					return processMap((Map)e.getValue(), key, version);
				}else {
					jsonObject.put(e.getKey(), processObj(e.getValue(), key, version));			
				}
			}
			jsonArray.add(jsonObject);
		}
		return jsonArray.toString();
	}

	/**
	 * 处理枚举字段
	 * @param value
	 * @param key
	 * @return
	 */
	@SuppressWarnings("unused")
	private static String processEnum(Enum<?> value, String key) {
		return null;
	}

	/**
	 * 处理数组字段
	 * @param key
	 * @param name
	 * @param value
	 * @return
	 * @throws MessageBizException
	 */
	private static String processArray(Object[] value, String key, String version)
			throws MessageBizException {
		List<Object> asList = null;
		if(null != value && value.length > 0){
			asList = Arrays.asList(value);
		}
		if(null != asList && !asList.isEmpty()){
			if(isPrimitive(asList.get(0).getClass())){
				return JSONArray.fromObject(value).toString();
			}
		}
		return processList(asList, key, version);
	}

	/**
	 * 判断map
	 * @param type
	 * @return
	 */
	private static boolean isMap(Class<?> type) {
		Class<? extends Map> asSubclass = null;
		try{
			asSubclass = type.asSubclass(Map.class);
		}catch(Exception e){
		}
		return asSubclass != null;
	}

	/**
	 * 判断集合
	 * @param type
	 * @return
	 */
	private static boolean isCollection(Class<?> type) {
		Class<? extends Collection> asSubclass = null;
		try{
			asSubclass = type.asSubclass(Collection.class);
		}catch(Exception e){
		}
		return asSubclass != null;
	}

	/**
	 * 判断非对象
	 * @param arg
	 * @return
	 */
	private static boolean isPrimitive(Class<?> arg){
		if(null == arg){
			return false;
		}
		if(
			arg.isPrimitive() ||
			arg.isAssignableFrom(String.class) ||
			arg.isAssignableFrom(Date.class) ||
			arg.isAssignableFrom(Boolean.class) ||
			arg.isAssignableFrom(Byte.class) ||
			arg.isAssignableFrom(Integer.class) ||
			arg.isAssignableFrom(Character.class) ||
			arg.isAssignableFrom(Short.class) ||
			arg.isAssignableFrom(Long.class) ||
			arg.isAssignableFrom(Double.class) ||
			arg.isAssignableFrom(Float.class)||
			arg.isAssignableFrom(BigDecimal.class)){
			return true;
		}else {
			return false;
		}
	}
	
	/**
	 * 判断数字
	 * @param arg
	 * @return
	 */
	private static boolean isNumeric(Class<?> arg){
		if(null == arg){
			return false;
		}
		if(
		    arg.isAssignableFrom(BigDecimal.class)||
			arg.isAssignableFrom(Byte.class) ||
			arg.isAssignableFrom(Integer.class) ||
			arg.isAssignableFrom(Character.class) ||
			arg.isAssignableFrom(Short.class) ||
			arg.isAssignableFrom(Long.class) ||
			arg.isAssignableFrom(Double.class) ||
			arg.isAssignableFrom(Float.class)){
			return true;
		}else {
			return false;
		}
	}
	
	/**
	 * 是否为日期类型
	 * @param type
	 * @return
	 */
	private static boolean isDate(Class<?> arg) {
		if(null == arg){
			return false;
		}
		if(arg.isAssignableFrom(Date.class)){
			return true;
		}else {
			return false;
		}
	}
	
	/**
	 * Class是否存在fieldName字段
	 * @param clz
	 * @param fieldName
	 * @return
	 */
	public static boolean existsField(Class clz,String fieldName){
	    try{
	        return clz.getDeclaredField(fieldName)!=null;
	    }
	    catch(Exception e){
	    }
	    if(clz!=Object.class){
	        return existsField(clz.getSuperclass(),fieldName);
	    }
	    return false;
	}
}
